home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- * Copyright (C) 1991, Silicon Graphics, Inc.
- * All Rights Reserved.
- */
-
- /*
- * playmidi - Play a MIDI file on a Hollywood/Magnum audio
- *
- * Contains routines:
- *
- * playtracks (aout, ntrks, tracks)
- * wf_init ()
- * read_ssf (file, samplebuf)
- * wl_init ()
- *
- * Jim Bennett
- * 1991
- */
-
- #include <audio.h>
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include "midif.h"
- #include "paths.h"
-
- extern float current_volume;
- extern int current_voice;
-
- extern int dographics;
- extern int maxvoices;
- extern int instruments [INSTRUMENTS];
- extern int keydowns []; /* Global state of key presses */
-
- /*
- * Table of currently active voices
- */
-
- static struct s_voice voices [2*MAX_VOICES];
-
- static short sbuf [SAMPLE_BUFSIZE];
-
- /*
- * Waveform tables, for quick lookup of waveforms
- */
-
- static float waveforms [5] [WFTABL*WF_REPLICATION];
- static float sinwave [WFTABL*WF_REPLICATION];
-
- /*
- * Per instrument pointers for waveform and amplitude
- */
-
- float *inst_wf [INSTRUMENTS];
- float *inst_ae [INSTRUMENTS];
- float *inst_off_ae [INSTRUMENTS];
-
- /*
- * Amplitude envelopes (time, value pairs, terminated with
- * a value of 0.0)
- */
-
- static float bell_key_down [] = {
- 0.01, 1.0,
- 0.2, 0.6,
- 0.75, 0.0
- };
-
- static float bell_key_up [] = {
- 0.03, 0.0
- };
-
- static float flute_key_down [] = {
- 0.04, 0.5,
- 0.4, 1.0,
- 1.0, 0.0
- };
-
- static float flute_key_up [] = {
- 0.01, 0.0
- };
-
- static float horn_key_down [] = {
- 0.02, 0.8,
- 0.04, 0.3,
- 0.06, 0.9,
- 0.18, 0.7,
- 0.30, 1.0,
- 0.8, 0.0
- };
-
- static float horn_key_up [] = {
- 0.01, 0.0
- };
-
- /*
- * Wavelength table, for conversion of MIDI pitch -> wavelength
- */
-
- static int wltab [256];
- static float wlistab [256];
-
- /*
- * Attenuate both volume and waveform with frequency
- */
-
- static float volume_attenuate [256];
- static float waveform_attenuate [256];
-
-
- /*
- * playtracks - Generate tones for all of the tracks
- */
-
- playtracks (aout, ntrks, tracks)
-
- ALport aout;
- int ntrks;
- struct s_ptrk *tracks;
-
- {
- struct s_mfevent *midi_event_ptr;
- int instrument, note, active;
- int double_maxvoices;
- int key_event;
- int total_voices;
- double t;
- float tupdate;
- float tdel;
- float evtime;
- float amp;
- int i, j;
- int lsamp, rsamp, wl, wli;
- long event;
- struct s_voice *freevoice;
- struct s_voice *vp;
- struct s_ptrk *trkp;
- struct s_finger *fp;
- struct s_finger *oldfp;
- int sbuf_ix = 0;
-
- /* Initialize instruments for each track. */
-
- printf ("\n");
- for (i=0; i<INSTRUMENTS; i++)
- {
- inst_wf[i] = waveforms[i%5];
- if ((i%3) == 0)
- {
- inst_ae[i] = flute_key_down;
- inst_off_ae[i] = flute_key_up;
- }
- else if ((i%3) == 1)
- {
- inst_ae[i] = bell_key_down;
- inst_off_ae[i] = bell_key_up;
- }
- else
- {
- inst_ae[i] = horn_key_down;
- inst_off_ae[i] = horn_key_up;
- }
- }
-
- total_voices = 0;
- for (i=0; i<ntrks; i++)
- {
- midi_event_ptr = tracks[i].base;
- tracks[i].evptr = midi_event_ptr;
-
- instrument = (midi_event_ptr->event >> 24) & 0x0f;
- if (midi_event_ptr->time < LONG_TIME)
- {
- printf ("Track %2d: %2d fingers, instrument %2d\n",
- i, tracks[i].nfingers, instrument);
- if (total_voices >= maxvoices)
- midi_event_ptr->time = END_TIME;
- else
- total_voices += tracks[i].nfingers;
- }
-
- /* Reassign instruments as directed */
-
- instrument = instruments[instrument];
-
- tracks[i].on_amp_env = inst_ae [instrument];
- tracks[i].off_amp_env = inst_off_ae [instrument];
-
- for (j=0; j<2*MAX_FINGERS; j++)
- {
- tracks[i].f[j].vp = NULL;
- tracks[i].f[j].finger = j;
- tracks[i].f[j].track = i;
- tracks[i].f[j].wftab = inst_wf [instrument];
- }
- }
-
- /* Initialize active voices list (place all voices on free list) */
-
- active = 0;
- freevoice = voices;
- for (i=0; i<2*MAX_VOICES; i++)
- {
- voices[i].fp = NULL;
- voices[i].next = &voices[i+1];
- }
- voices[(2*MAX_VOICES)-1].next = NULL;
-
- /* Tracks initialized, start at the begining of time and loop until end */
-
- t = 0.0;
- tdel = 1.0 / (double)SYNTHIA_RATE;
- tupdate = 0.0;
- double_maxvoices = 2*maxvoices;
- key_event = 0;
-
- while (1)
- {
-
- /* Get the time of the next event, exit if end of time */
-
- evtime = END_TIME;
- for (i=0,trkp=tracks; i<ntrks; i++,trkp++)
- if ((trkp->evptr)->time < evtime)
- evtime = (trkp->evptr)->time;
-
- if (evtime > LONG_TIME)
- {
- if (sbuf_ix > 0)
- ALwritesamps (aout, sbuf, sbuf_ix);
- return;
- }
-
- /* To quantize events somewhat: */
- /* evtime += 0.003; */
-
- /* Loop until time passes next event time */
-
- for (; t<evtime; t+= tdel, tupdate += tdel)
- {
- if (dographics && (tupdate > 0.05))
- {
- tupdate = 0.0;
- check_input ();
- if (key_event)
- {
- key_event = 0;
- hilight_keys (&keydowns[(MIDDLE_C-24)]);
- }
- }
- lsamp = 0;
- rsamp = 0;
- for (i=0,vp=voices; i<double_maxvoices; i++,vp++)
- {
- if (vp->fp)
- {
- fp = vp->fp;
-
- /* Process voice */
-
- if (fp->track & 0x01)
- {
- lsamp = lsamp +
- (fp->atten * (fp->val * fp->wftab [(int)(fp->wli*fp->wlis)])) +
- (fp->catten * (fp->val * sinwave [(int)(fp->wli*fp->wlis)]));
- }
- else
- {
- rsamp = rsamp +
- (fp->atten * (fp->val * fp->wftab [(int)(fp->wli*fp->wlis)])) +
- (fp->catten * (fp->val * sinwave [(int)(fp->wli*fp->wlis)]));
- }
- fp->wli++;
- if (fp->wli >= fp->wl) fp->wli = 0;
- fp->t += tdel;
- fp->val += fp->vdel;
- if (fp->t >= *fp->aeptr)
- {
- fp->aeptr++;
- if (*fp->aeptr > 0.01)
- {
- fp->val = *fp->aeptr++;
- fp->vdel = tdel *
- (fp->aeptr[1] - fp->aeptr[-1]) / (fp->aeptr[0] - fp->aeptr[-2]);
- }
- else
- {
- fp->vp = NULL; /* Turn this voice off */
- vp->fp = NULL;
- vp->next = freevoice;
- freevoice = vp;
- if (vp->keydown)
- {
- key_event = 1;
- keydowns[fp->note]--;
- active--;
- }
- }
- }
- }
- }
- sbuf[sbuf_ix++] = lsamp;
- sbuf[sbuf_ix++] = rsamp;
- if (sbuf_ix >= SAMPLE_BUFSIZE)
- {
- ALwritesamps (aout, sbuf, sbuf_ix);
- sbuf_ix = 0;
- }
- }
-
- /* Initiate events */
-
- for (i=0,trkp=tracks; i<ntrks; i++,trkp++)
- {
- while ((trkp->evptr)->time <= evtime)
- {
- event = (trkp->evptr)->event;
- note = event&0x7f;
- fp = trkp->f;
- fp = &fp[(event >> 28) & 0x0f];
-
- if (((event >> 16)&0xff) == NOTE_ON)
- {
- if (active < maxvoices)
- {
- #ifdef DEBUG
- if (fp->vp)
- printf ("# %d\n", (event >> 28) & 0x0f);
- #endif
- freevoice->fp = fp;
- freevoice->keydown = 1;
- fp->vp = freevoice;
- freevoice = freevoice->next;
- fp->note = note;
- fp->wl = wltab[note];
-
- key_event = 1;
- keydowns[note]++;
- active++;
-
- fp->wlis = wlistab[note];
- fp->atten =
- waveform_attenuate[note];
- fp->catten = 1.0 - fp->atten;
- amp =
- volume_attenuate[note] * current_volume * (5000 + ((event>>8)&0x7f)*100);
- fp->atten = amp*fp->atten;
- fp->catten = amp*fp->catten;
-
- fp->aeptr = trkp->on_amp_env;
- if (current_voice != -1)
- {
- fp->wftab =
- inst_wf[current_voice];
- fp->aeptr =
- inst_ae[current_voice];
- }
-
- fp->wli = 0;
- fp->t = 0.0;
- fp->val = 0.0;
- fp->vdel = tdel *
- (fp->aeptr[1] / fp->aeptr[0]);
- }
- }
- else
- { /* Else NOTE_OFF event */
- if (fp->vp)
- {
- vp = fp->vp;
- oldfp = fp;
- oldfp->vp = NULL;
- fp = &fp[MAX_FINGERS];
- if (fp->vp)
- {
- #ifdef DEBUG
- printf ("- %d %d\n", fp->finger, fp->vp->fp->finger);
- #endif
-
- /* Previous note still lingering, shut it down */
-
- fp->vp->fp = NULL;
- fp->vp->next = freevoice;
- freevoice = fp->vp;
- fp->vp = NULL;
- }
- vp->fp = fp;
- vp->keydown = 0;
- fp->vp = vp;
- fp->wl = oldfp->wl;
-
- key_event = 1;
- keydowns[note]--;
- active--;
-
- fp->wlis = oldfp->wlis;
- fp->atten = oldfp->atten;
- fp->catten = oldfp->catten;
-
- fp->aeptr = trkp->off_amp_env;
- if (current_voice != -1)
- {
- fp->wftab =
- inst_wf[current_voice];
- fp->aeptr =
- inst_off_ae[current_voice];
- }
-
- fp->wli = oldfp->wli;
- fp->t = 0.0;
- fp->val = oldfp->val;
- fp->vdel = tdel *
- ((fp->aeptr[1] - fp->val) / fp->aeptr[0]);
- }
- }
- trkp->evptr++;
- }
- }
- }
- }
-
- /*
- * wf_init - Initialize waveform tables
- *
- * wf_init generates 5 synthetic waveforms, and
- * then overwrites these with sampled waveforms,
- * if they are found.
- */
-
- wf_init ()
-
- {
- int i, j;
- int tmod = WF_REPLICATION*WFTABL;
-
- /* Table 0: Sin wave with 1/6, 1/3, and 1/2 harmonics */
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- sinwave[i] =
- 0.01 * sin((i*2.0*M_PI)/(WFTABL*6)) +
- 0.02 * sin((i*2.0*M_PI)/(WFTABL*3)) +
- 0.03 * sin((i*2.0*M_PI)/(WFTABL*2)) +
- 0.85 * sin((i*2.0*M_PI)/WFTABL);
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- sinwave[i] +=
- 0.01 * (((drand48() + drand48() + drand48() + drand48()) / 2.0) - 1.0);
-
- /* Apply smoother */
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- waveforms[0][i] = 0.05*sinwave[(i+tmod-2)%tmod] +
- 0.20*sinwave[(i+tmod-1)%tmod] +
- 0.30*sinwave[i] +
- 0.20*sinwave[(i+1)%tmod];
- 0.05*sinwave[(i+2)%tmod];
-
-
- /* Table 1: Spiky wave */
- for (j=0; j<WF_REPLICATION; j++)
- {
- for (i=0; i<WFTABL/5; i++)
- sinwave[(j*WFTABL)+i] = 0.0;
- for (; i<(2*WFTABL)/5; i++)
- sinwave[(j*WFTABL)+i] =
- ((float)(i-WFTABL/5) * 5.0) / (float)WFTABL;
- for (; i<(3*WFTABL)/5; i++)
- sinwave[(j*WFTABL)+i] =
- 1.0 - (((float)(i-(2*WFTABL)/5) * 10.0) /
- (float)WFTABL);
- for (; i<(4*WFTABL)/5; i++)
- sinwave[(j*WFTABL)+i] =
- (((float)(i-(3*WFTABL)/5) * 5.0) /
- (float)WFTABL) - 1.0;
- for (; i<WFTABL; i++)
- sinwave[(j*WFTABL)+i] = 0.0;
- }
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- sinwave[i] +=
- 0.02 * (((drand48() + drand48() + drand48() + drand48()) / 2.0) - 1.0);
-
- /* Apply smoother */
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- waveforms[1][i] = 0.05*sinwave[(i+tmod-2)%tmod] +
- 0.20*sinwave[(i+tmod-1)%tmod] +
- 0.30*sinwave[i] +
- 0.20*sinwave[(i+1)%tmod];
- 0.05*sinwave[(i+2)%tmod];
-
-
- /* Table 2: Saw tooth wave with 1/2 harmonic */
- for (j=0; j<WF_REPLICATION; j++)
- {
- for (i=0; i<WFTABL/5; i++)
- sinwave[(j*WFTABL)+i] =
- (((float)i * 10.0) / (float)WFTABL) - 1.0;
- for (; i<WFTABL; i++)
- sinwave[(j*WFTABL)+i] =
- 1.0 - (((i-WFTABL/5) * 10.0) /
- (4.0 * (float)WFTABL));
- }
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- sinwave[i] +=
- 0.02 * sin((i*2.0*M_PI)/(WFTABL*2));
-
- /* Apply smoother */
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- waveforms[2][i] = 0.05*sinwave[(i+tmod-2)%tmod] +
- 0.20*sinwave[(i+tmod-1)%tmod] +
- 0.30*sinwave[i] +
- 0.20*sinwave[(i+1)%tmod];
- 0.05*sinwave[(i+2)%tmod];
-
- /* Table 3: Square wave with 1/6, 1/3, and 1/2 sin harmonics */
- for (j=0; j<WF_REPLICATION; j++)
- {
- for (i=0; i<WFTABL/5; i++)
- sinwave[(j*WFTABL)+i] = -1.0;
- for (; i<(3*WFTABL)/10; i++)
- sinwave[(j*WFTABL)+i] =
- ((float)(i-WFTABL/5)*20.0 /
- (float)WFTABL) - 1.0;
- for (; i<(7*WFTABL)/10; i++)
- sinwave[(j*WFTABL)+i] = 1.0;
- for (; i<(8*WFTABL)/10; i++)
- sinwave[(j*WFTABL)+i] =
- 1.0 - ((float)(i-(7*WFTABL)/10)*20.0 /
- (float)WFTABL);
- for (; i<WFTABL; i++)
- sinwave[(j*WFTABL)+i] = -1.0;
- }
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- sinwave[i] =
- 0.80 * sinwave[i] +
- 0.00 * sin((i*2.0*M_PI)/(WFTABL*6)) +
- 0.01 * sin((i*2.0*M_PI)/(WFTABL*3)) +
- 0.02 * sin((i*2.0*M_PI)/(WFTABL*2)) +
- 0.02 * (((drand48() + drand48() + drand48() + drand48()) / 2.0) - 1.0);
-
- /* Apply smoother */
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- waveforms[3][i] = 0.05*sinwave[(i+tmod-2)%tmod] +
- 0.20*sinwave[(i+tmod-1)%tmod] +
- 0.30*sinwave[i] +
- 0.20*sinwave[(i+1)%tmod];
- 0.05*sinwave[(i+2)%tmod];
-
-
- /* Table 4: Sin wave with 1/6, 1/3, and 1/2 harmonics */
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- sinwave[i] =
- 0.01 * sin((i*2.0*M_PI)/(WFTABL*6)) +
- 0.02 * sin((i*2.0*M_PI)/(WFTABL*3)) +
- 0.03 * sin((i*2.0*M_PI)/(WFTABL*2)) +
- 0.85 * sin((i*2.0*M_PI)/WFTABL);
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- sinwave[i] +=
- 0.01 * (((drand48() + drand48() + drand48() + drand48()) / 2.0) - 1.0);
-
- /* Apply smoother */
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- waveforms[4][i] = 0.05*sinwave[(i+tmod-2)%tmod] +
- 0.20*sinwave[(i+tmod-1)%tmod] +
- 0.30*sinwave[i] +
- 0.20*sinwave[(i+1)%tmod];
- 0.05*sinwave[(i+2)%tmod];
-
-
- /* We have generated the waves, now check for samples */
-
- read_ssf ("0.ssf", waveforms[0]);
- read_ssf ("1.ssf", waveforms[1]);
- read_ssf ("2.ssf", waveforms[2]);
- read_ssf ("3.ssf", waveforms[3]);
- read_ssf ("4.ssf", waveforms[4]);
-
- /* Then put a sin wave into sinwave (at 1/2 frequency) */
-
- for (i=0; i<WF_REPLICATION*WFTABL; i++)
- sinwave[i] = sin((i*2.0*M_PI)/(WFTABL*2));
- }
-
- /*
- * read_ssf - Read in waveform from file into buffer
- *
- * Returns 1 if error
- */
-
- read_ssf (fname, fbuf)
-
- char *fname;
- float *fbuf;
-
- {
- FILE *ssf;
- char *buf;
- char *path;
- int ret;
- float samprate;
- float incount;
- int icnt;
-
- ssf = fopen (fname, "r");
- if ((ssf == NULL) && (*fname != '/'))
- {
- if (!(path = getenv("SYNTHIA_SOUND_PATH")))
- path = SOUND_PATH;
- buf = (char *)malloc (strlen(fname) + strlen(path) + 2);
- strcpy (buf, path);
- strcat (buf, "/");
- strcat (buf, fname);
- ssf = fopen (buf, "r");
- }
- if (ssf == NULL) return (1);
-
- ret = fread (&samprate, sizeof(float), 1, ssf);
- if (ret != 1) return (1);
-
- ret = fread (&incount, sizeof(float), 1, ssf);
- if (ret != 1) return (1);
-
- icnt = incount;
- if (icnt != WF_REPLICATION*WFTABL) return (1);
-
- ret = fread (fbuf, sizeof(float), icnt, ssf);
- if (ret != icnt) return (1);
-
- /* File read into sample buffer, all is OK */
-
- return (0);
- }
-
- /*
- * wl_init - Initialize wavelength table
- */
-
- wl_init ()
-
- {
- int i, j;
- int hz;
- double exptab[12]; /* For the 12th roots of two */
- float dhz;
-
- for (i=0; i<12; i++)
- exptab[i] = pow (2.0, (double)i/12.0);
- for (i=0; i<(A_ABOVE-36); i++) /* Tones too low */
- {
- wltab[i] = 0;
- wlistab[i] = 0.0;
- volume_attenuate[i] = 1.0;
- waveform_attenuate[i] = 1.0;
- }
-
- /* Start at 3 octaves below A (the A above middle C) */
- /* Each octave is 12 halftones, and the frequency doubles */
-
- for (hz=(A_HZ>>3), i=(A_ABOVE-36); i<128; i+=12, hz *= 2)
- {
- for (j=0; j<12; j++)
- {
- dhz = hz * exptab[j];
- wltab[i+j] = (float)SYNTHIA_RATE/dhz;
- wlistab[i+j] = (float)WFTABL/(float)wltab[i+j];
- wltab[i+j] *= WF_REPLICATION;
-
- if ((i+j) >= MIDDLE_C+48)
- volume_attenuate[i+j] = 0.0;
- else
- if ((i+j) > MIDDLE_C)
- volume_attenuate[i+j] = 1.0 -
- ((float)((i+j)-MIDDLE_C) / 48.0);
- else
- volume_attenuate[i+j] = 1.0;
-
- if ((i+j) >= MIDDLE_C+30)
- waveform_attenuate[i+j] = 0.0;
- else
- if ((i+j) > MIDDLE_C-6)
- waveform_attenuate[i+j] = 1.0 -
- ((float)((i+j)-(MIDDLE_C-6)) / 36.0);
- else
- waveform_attenuate[i+j] = 1.0;
- }
- }
- }
-